﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Site.Models;

namespace Site.Controllers
{
    public class AccountController : Controller
    {
        private BMSiteDBEntities _db = new BMSiteDBEntities();

        //Index
        [Authorize]
        public ActionResult Index()
        {
            var admin_role = _db.aspnet_Roles.First(m => m.RoleName == "Administrator");
            var players = (
                from r in _db.vw_aspnet_UsersInRoles
                join u in _db.aspnet_Users on r.UserId equals u.UserId
                where r.RoleId != admin_role.RoleId
                select u
                ).ToList();
            return View(players);
        }



        // GET: /Account/Details/5
        [AcceptVerbs(HttpVerbs.Get)]
        [Authorize]
        public ActionResult Details(System.Guid id)
        {
            var current_user = _db.aspnet_Users.FirstOrDefault(m => m.UserId == id);
            var id_user_connected = new Guid(Session.Contents["user_id"].ToString());
            ProfileUser model = new ProfileUser
            {
                user = current_user,
                stats = (
                    from s in _db.STATISTIC
                    where s.STAT_USER_ID == current_user.UserId
                    select s
                ).ToList(),
                clan = _db.CLAN.FirstOrDefault(m => m.CLAN_ID == current_user.USER_CLAN_ID),
                friend = (
                    from a in _db.FRIEND
                    where a.FRIEND_ID == id
                    where a.FRIEND_USER_ID == id_user_connected
                    select a
                ).FirstOrDefault()
            };
            
            return View(model);
        }

        // GET: /Account/Edit/5
        [Authorize]
        public ActionResult Edit(System.Guid id)
        {
            var accountToEdit = _db.aspnet_Users.First(m => m.UserId == id);

            /* Converting asp_user model to edit model to use validator classes */
            var EditModel = new EditModel();
            EditModel.Avatar = accountToEdit.USER_AVATAR;
            EditModel.Birthday = (DateTime)accountToEdit.USER_BIRTHDAY;
            EditModel.City = accountToEdit.USER_CITY;
            EditModel.Country = accountToEdit.USER_COUNTRY;
            EditModel.Email = accountToEdit.USER_MAIL;
            EditModel.UserName = accountToEdit.UserName;
            EditModel.UserId = accountToEdit.UserId;

            return View(EditModel);
        }

        //
        // POST: /Account/Edit/5

        [AcceptVerbs(HttpVerbs.Post)]
        [Authorize]
        public ActionResult Edit(EditModel accountToEdit)
        {
            if (string.IsNullOrEmpty(accountToEdit.UserName))
                ViewData.ModelState.AddModelError("UserName", "Le pseudo est requis!!");

            if (!ModelState.IsValid)
                return View();

            try
            {
                var originalAccount = _db.aspnet_Users.First(m => m.UserId == accountToEdit.UserId);
                originalAccount.UserName = accountToEdit.UserName;
                originalAccount.USER_MAIL = accountToEdit.Email;
                originalAccount.USER_BIRTHDAY = accountToEdit.Birthday;
                originalAccount.USER_COUNTRY = accountToEdit.Country;
                originalAccount.USER_CITY = accountToEdit.City;

                var membership_obj = _db.aspnet_Membership.First(m => m.UserId == accountToEdit.UserId);
                membership_obj.Email = accountToEdit.Email;
                membership_obj.LoweredEmail = accountToEdit.Email.ToLower();

                originalAccount.USER_AVATAR = accountToEdit.Avatar;

                var file_path = "";
                var file_url = "";
                HttpPostedFileBase file = Request.Files["avatar_upload_file"];
                if (file != null  && file.ContentLength > 0)
                {
                    file_path = Server.MapPath("~") + "/Uploads/avatars/" + accountToEdit.UserId + ".jpg";
                    file_url = "http://" + Request.Url.Authority + "/Uploads/avatars/" + accountToEdit.UserId + ".jpg";
                    file.SaveAs(file_path);
                    originalAccount.USER_AVATAR = file_url;
                }

                _db.SaveChanges();

                return RedirectToAction("details/" + originalAccount.UserId);
            }
            catch
            {
                return View();
            }
        }


        //
        // GET: /Account/LogOn

        public ActionResult LogOn()
        {
            return View();
        }

        //
        // POST: /Account/LogOn

        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    //Putting current user's id in session
                    var currentUser = _db.aspnet_Users.First(m => m.UserName == model.UserName);
                    Session.Contents["user_id"] = currentUser.UserId.ToString();
                    Session.Contents["uid"] = currentUser.USER_WS_ID;

                    /* If user has a clan, put his in*/
                    if (currentUser.USER_CLAN_ID != null) { Session.Contents["userClanId"] = currentUser.USER_CLAN_ID; }

                    /* Updating users account */
                    currentUser.USER_LASTCONNECTION = System.DateTime.Now;
                    currentUser.USER_ISCONNECTED = 1;

                    if (TryUpdateModel(currentUser))
                    {
                        _db.ApplyCurrentValues(currentUser.EntityKey.EntitySetName, currentUser);
                        _db.SaveChanges();
                    }
                    /* ************************************************ */

                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "Le nom d'utilisateur ou mot de passe fourni est incorrect.");
                }
            }

            return View();
        }

        //
        // GET: /Account/LogOff
        [Authorize]
        public ActionResult LogOff()
        {

            if (Session.Contents["user_id"] != null)
            {
                //Catching current user
                var test = Session.Contents["user_id"];
                Guid user_id = new Guid(test.ToString());
                var currentUser = _db.aspnet_Users.First(m => m.UserId == user_id);

                //Deleting users id and clan id in session
                Session.Contents["user_id"] = "";
                Session.Contents["userClanId"] = "";

                /* Updating user's account */
                currentUser.USER_ISCONNECTED = 0;

                if (TryUpdateModel(currentUser))
                {
                    _db.ApplyCurrentValues(currentUser.EntityKey.EntitySetName, currentUser);
                    _db.SaveChanges();
                }
                /* ************************************************ */
            }
            FormsAuthentication.SignOut();

            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/Register

        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        //[HttpPost]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Register attempt by the user
                MembershipCreateStatus createStatus;
                Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

                if (createStatus == MembershipCreateStatus.Success)
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
                    
                    /* ****** Add our model's datas ***** */
                    var user_created = _db.aspnet_Users.First(m => m.UserName == model.UserName);
                    user_created.USER_COUNTRY = model.Country;
                    user_created.USER_CITY = model.City;
                    user_created.USER_BIRTHDAY = DateTime.ParseExact(model.Birthday, "MM/dd/yyyy", null);
                    user_created.USER_MAIL = model.Email;
                    user_created.USER_WS_ID = 0;

                    /* ****** Avatar ****** */
                    var file_path = "";
                    var file_url = "";
                    HttpPostedFileBase file = Request.Files["avatar_upload_file"];
                    if (file != null) {
                        file_path = Server.MapPath("~") + "/Uploads/avatars/" + user_created.UserId + ".jpg";
                        file_url = "http://" + Request.Url.Authority + "/Uploads/avatars/" + user_created.UserId + ".jpg";
                        file.SaveAs(file_path);
                    }

                    var avatar_type = Request.Form["avatar_type"];
                    if (avatar_type == "avatar_url")
                    {
                        user_created.USER_AVATAR = model.Avatar;
                    }
                    else if (avatar_type == "avatar_upload")
                    {
                        user_created.USER_AVATAR = file_url;
                    }
                    
                    /*  ******* Add basics parameters ******* */
                    user_created.USER_ISACTIVE = 1;
                    user_created.USER_CREATIONDATE = System.DateTime.Now;

                    Roles.AddUserToRole(user_created.UserName, "member");

                    if (TryUpdateModel(user_created))
                    {
                        _db.ApplyCurrentValues(user_created.EntityKey.EntitySetName, user_created);
                        _db.SaveChanges();
                    }
                    /* ************************************************* */

                    /* Configure users's id in session */
                    Session.Contents["user_id"] = user_created.UserId;

                    /* Add null stats */
                    STATISTIC stats1 = new STATISTIC();
                    stats1.STAT_USER_ID = user_created.UserId;
                    stats1.STAT_ABANDONEDGAMES = 0;
                    stats1.STAT_LOSTGAMES = 0;
                    stats1.STAT_WONGAMES = 0;
                    stats1.STAT_GAMETYPE = 1;
                    STATISTIC stats2 = new STATISTIC();
                    stats2.STAT_USER_ID = user_created.UserId;
                    stats2.STAT_ABANDONEDGAMES = 0;
                    stats2.STAT_LOSTGAMES = 0;
                    stats2.STAT_WONGAMES = 0;
                    stats2.STAT_GAMETYPE = 2;
                    STATISTIC stats3 = new STATISTIC();
                    stats3.STAT_USER_ID = user_created.UserId;
                    stats3.STAT_ABANDONEDGAMES = 0;
                    stats3.STAT_LOSTGAMES = 0;
                    stats3.STAT_WONGAMES = 0;
                    stats3.STAT_GAMETYPE = 3;
                    STATISTIC stats4 = new STATISTIC();
                    stats4.STAT_USER_ID = user_created.UserId;
                    stats4.STAT_ABANDONEDGAMES = 0;
                    stats4.STAT_LOSTGAMES = 0;
                    stats4.STAT_WONGAMES = 0;
                    stats4.STAT_GAMETYPE = 4;

                    if (TryUpdateModel(stats1) && TryUpdateModel(stats2) && TryUpdateModel(stats3) && TryUpdateModel(stats4))
                    {
                        _db.AddObject("STATISTIC", stats1);
                        _db.AddObject("STATISTIC", stats2);
                        _db.AddObject("STATISTIC", stats3);
                        _db.AddObject("STATISTIC", stats4);
                        _db.SaveChanges();
                    }

                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", ErrorCodeToString(createStatus));
                }
            }

            return View(model);
        }

        //
        // GET: /Account/ChangePassword

        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }

        //
        // POST: /Account/ChangePassword

        [Authorize]
        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {

                bool changePasswordSucceeded;
                try
                {
                    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("", "Le mot de passe actuel est incorrect ou le nouveau mot de passe n'est pas valide.");
                }
            }

            return View(model);
        }

        //
        // GET: /Account/ChangePasswordSuccess
        [Authorize]
        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }


        //
        // GET: //RetreivePassword
        public ActionResult RetreivePassword()
        {
            return View();
        }

        //
        // POST: /Account/RetreivePassword

        [HttpPost]
        public ActionResult RetreivePassword(String mail)
        {
            var email = Request.Form["email"];
            var user = Membership.FindUsersByEmail(email);

            if (user.Count > 0)
            {
                MembershipUser currentUser = Membership.GetUser(Membership.GetUserNameByEmail(email), true /* userIsOnline */); 
                var new_pass = currentUser.ResetPassword();

                /* send mail here */

                return View("RetreiveSuccess");
            }
            else {
                return View("RetreiveFail");
            }
        }

        //
        // GET: //Account/Unsubscribe
        public ActionResult Unsubscribe()
        {
            return View();
        }

        //
        // POST: /Account/Unsubscribe

        [HttpPost]
        public ActionResult Unsubscribe(String mail)
        {
            var unsuscribe_response = Request.Form["unsuscribe_response"];
            if (unsuscribe_response == "yes") {
                var user = Membership.DeleteUser(User.Identity.Name);
                return View("LogOn");
            }
            else {
                return RedirectToAction("Index", "Home");
            }
        }

        //
        // POST: /Account/ChangeRole/5

        [HttpPost]
        public ActionResult ChangeRole()
        {
            //Look for old Role
            var userId = new Guid(Request.Form["UserId"]);
            var userInRole = _db.vw_aspnet_UsersInRoles.First(m => m.UserId == userId);
            var oldRole = _db.aspnet_Roles.First(m => m.RoleId == userInRole.RoleId);
                        
            Roles.RemoveUserFromRole(Request.Form["UserName"], oldRole.RoleName);
            Roles.AddUserToRole(Request.Form["UserName"], Request.Form["role"]);

            return RedirectToAction("details/" + Request.Form["ClanId"], "Clan");
        }

        //FriendList
        [Authorize]
        public ActionResult FriendList()
        {
            var userID = new Guid(Session.Contents["user_id"].ToString());
            var friends = (
                   from tb1 in _db.FRIEND
                   join tb2 in _db.aspnet_Users on tb1.FRIEND_ID equals tb2.UserId
                   where tb1.FRIEND_USER_ID == userID
                   select new FriendList {user = tb2, friend = tb1 }
                ).ToList();
            return View(friends);
        }

        //
        // GET: //Account/AddFriend/5
        public ActionResult AddFriend(System.Guid id)
        {
            var friend = _db.aspnet_Users.First(m => m.UserId == id);
            return View(friend);
        }

        //
        // POST: /Account/AddFriend

        [HttpPost]
        public ActionResult AddFriend()
        {
            /** Friend_accepted : 
            * 0 : not accepted
            * 1 : request sent
            * 2 : accepted
            * ***************** */
            
            /* User who wants to be friend */
            var friend_1 = new FRIEND();
            friend_1.FRIEND_ID = new Guid(Request.Form["UserId"].ToString());
            friend_1.FRIEND_USER_ID = new Guid(Session.Contents["user_id"].ToString());
            friend_1.FRIEND_ACCEPTED = 1;

            /* User who needs to accepts request */
            var friend_2 = new FRIEND();
            friend_2.FRIEND_ID = new Guid(Session.Contents["user_id"].ToString());
            friend_2.FRIEND_USER_ID = new Guid(Request.Form["UserId"].ToString());
            friend_2.FRIEND_ACCEPTED = 0;

            if (TryUpdateModel(friend_1) && TryUpdateModel(friend_2))
            {
                _db.AddObject("FRIEND", friend_1);
                _db.AddObject("FRIEND", friend_2);
                _db.SaveChanges();
            }

            return RedirectToAction("FriendList", "Account");
        }

        //
        // GET: //Account/DeleteFriend/5
        public ActionResult DeleteFriend(System.Guid id)
        {
            var friend = _db.aspnet_Users.First(m => m.UserId == id);
            return View(friend);
        }

        //
        // POST: /Account/DeleteFriend

        [HttpPost]
        public ActionResult DeleteFriend()
        {
            
            var friend_id = new Guid(Request.Form["UserId"].ToString());
            var current_user_id = new Guid(Session.Contents["user_id"].ToString());
            
            var friend = (
                    from a in _db.FRIEND
                    where a.FRIEND_ID == friend_id
                    where a.FRIEND_USER_ID == current_user_id
                    select a
                ).First();

            if (TryUpdateModel(friend))
            {
                _db.DeleteObject(friend);
                _db.SaveChanges();
            }

            return RedirectToAction("FriendList", "Account");
        }

        //
        // GET: //Account/AcceptFriend/5
        public ActionResult AcceptFriend(System.Guid id)
        {
            var friend = _db.aspnet_Users.First(m => m.UserId == id);
            return View(friend);
        }

        //
        // POST: /Account/AcceptFriend

        [HttpPost]
        public ActionResult AcceptFriend()
        {
            var friend_id = new Guid(Request.Form["UserId"].ToString());
            var current_user_id = new Guid(Session.Contents["user_id"].ToString());

            /* User who wants to be friend */
            var friend_1 = (
                    from a in _db.FRIEND
                    where a.FRIEND_ID == friend_id
                    where a.FRIEND_USER_ID == current_user_id
                    select a
                ).First();
            friend_1.FRIEND_ACCEPTED = 2;

            /* User who wants to be friend */
            var friend_2 = (
                    from a in _db.FRIEND
                    where a.FRIEND_ID == current_user_id
                    where a.FRIEND_USER_ID == friend_id
                    select a
                ).First();
            friend_2.FRIEND_ACCEPTED = 2;

            if (TryUpdateModel(friend_1) && TryUpdateModel(friend_2))
            {
                _db.SaveChanges();
            }

            return RedirectToAction("FriendList", "Account");
        }

        #region Status Codes
        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // Consultez http://go.microsoft.com/fwlink/?LinkID=177550 pour
            // obtenir la liste complète des codes d'état.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Le nom d'utilisateur existe déjà. Entrez un nom d'utilisateur différent.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Un nom d'utilisateur pour cette adresse de messagerie existe déjà. Entrez une adresse de messagerie différente.";

                case MembershipCreateStatus.InvalidPassword:
                    return "Le mot de passe fourni n'est pas valide. Entrez une valeur de mot de passe valide.";

                case MembershipCreateStatus.InvalidEmail:
                    return "L'adresse de messagerie fournie n'est pas valide. Vérifiez la valeur et réessayez.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "La réponse de récupération du mot de passe fournie n'est pas valide. Vérifiez la valeur et réessayez.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "La question de récupération du mot de passe fournie n'est pas valide. Vérifiez la valeur et réessayez.";

                case MembershipCreateStatus.InvalidUserName:
                    return "Le nom d'utilisateur fourni n'est pas valide. Vérifiez la valeur et réessayez.";

                case MembershipCreateStatus.ProviderError:
                    return "Le fournisseur d'authentification a retourné une erreur. Vérifiez votre entrée et réessayez. Si le problème persiste, contactez votre administrateur système.";

                case MembershipCreateStatus.UserRejected:
                    return "La demande de création d'utilisateur a été annulée. Vérifiez votre entrée et réessayez. Si le problème persiste, contactez votre administrateur système.";

                default:
                    return "Une erreur inconnue s'est produite. Vérifiez votre entrée et réessayez. Si le problème persiste, contactez votre administrateur système.";
            }
        }
        #endregion
    }
}
